home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgramD2.iso
/
Borland
/
Borland C++ V5.02
/
CLASSSRC.PAK
/
REGISTRY.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-06
|
21KB
|
811 lines
//----------------------------------------------------------------------------
// Borland WinSys Library
// Copyright (c) 1994, 1997 by Borland International, All Rights Reserved
//
//$Revision: 5.22 $
//
// General Registry access & registration implementation
//----------------------------------------------------------------------------
#include <winsys/pch.h>
#include <winsys/registry.h>
#include <winsys/system.h>
#include <classlib/pointer.h>
#include <services/checks.h>
#include <stdlib.h> // atol()
#include <tchar.h>
//#include <stdio.h> // sprintf()
//
// Predefined constant registry keys
//
#if defined(BI_PLAT_WIN16)
# define HKEY_CURRENT_USER ((HKEY)0x80000001L)
# define HKEY_LOCAL_MACHINE ((HKEY)0x80000002L)
# define HKEY_USERS ((HKEY)0x80000003L)
# define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004L)
# define HKEY_PERFORMANCE_TEXT ((HKEY)0x80000050L)
# define HKEY_PERFORMANCE_NLSTEXT ((HKEY)0x80000060L)
# define HKEY_CURRENT_CONFIG ((HKEY)0x80000005L)
# define HKEY_DYN_DATA ((HKEY)0x80000006L)
TRegKey TRegKey::ClassesRoot((TSystem::IsWin95())? ((HKEY)0x80000000L):
HKEY_CLASSES_ROOT, true, "HKEY_CLASSES_ROOT");
#else
TRegKey TRegKey::ClassesRoot(HKEY_CLASSES_ROOT, true, "HKEY_CLASSES_ROOT");
#endif
TRegKey TRegKey::ClassesRootClsid(ClassesRoot, "CLSID", KEY_ALL_ACCESS, NoCreate);
//
//
//
TRegKey&
TRegKey::GetClassesRoot()
{
return ClassesRoot;
}
//
//
//
TRegKey&
TRegKey::GetClassesRootClsid()
{
return ClassesRootClsid;
}
//
//
//
TRegKey&
TRegKey::GetCurrentUser()
{
static TRegKey CurrentUser(HKEY_CURRENT_USER, true, "HKEY_CURRENT_USER");
return CurrentUser;
}
//
//
//
TRegKey&
TRegKey::GetLocalMachine()
{
static TRegKey LocalMachine(HKEY_LOCAL_MACHINE, true, "HKEY_LOCAL_MACHINE");
return LocalMachine;
}
//
//
//
TRegKey&
TRegKey::GetUsers()
{
static TRegKey Users(HKEY_USERS, true, "HKEY_USERS");
return Users;
}
//
//
//
TRegKey&
TRegKey::GetCurrentConfig()
{
static TRegKey CurrentConfig(HKEY_CURRENT_CONFIG, true, "HKEY_CURRENT_CONFIG");
return CurrentConfig;
}
//
//
//
TRegKey&
TRegKey::GetDynData()
{
static TRegKey DynData(HKEY_DYN_DATA, true, "HKEY_DYN_DATA");
return DynData;
}
//
//
//
TRegKey&
TRegKey::GetPerformanceData()
{
static TRegKey PerformanceData(HKEY_PERFORMANCE_DATA, true, "HKEY_PERFORMANCE_DATA");
return PerformanceData;
}
//
// Different parameter usage & initial code for Win16 vs Win32
//
#if defined(BI_PLAT_WIN16)
//
// Initialize the object with the passed-in data.
//
TRegKey::TRegKey(THandle baseKey, const _TCHAR far* keyName, REGSAM /*samDesired*/, TCreateOK createOK)
:
Name(strnewdup(keyName)),
Key(0)
{
if (createOK == CreateOK) {
::RegCreateKey(baseKey, Name, &Key);
}
else
::RegOpenKey(baseKey, Name, &Key);
#else
//
// Initialize the object with the passed-in data.
//
TRegKey::TRegKey(THandle baseKey, const _TCHAR far* keyName, REGSAM samDesired, TCreateOK createOK)
:
Name(strnewdup(keyName)),
Key(0)
{
if (createOK == CreateOK) {
uint32 disposition;
::RegCreateKeyEx(baseKey, Name, 0, ""/*class*/, REG_OPTION_NON_VOLATILE,
samDesired, 0/*SecurityAttributes*/, &Key,
&disposition);
}
else
::RegOpenKeyEx(baseKey, Name, 0, samDesired, &Key);
#endif
QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
ShouldClose = true;
// TXRegistry::Check(long(Key), Name);
}
//
// Initialize object with the key pointed to by the iterator.
//
#if defined(BI_PLAT_WIN16)
TRegKey::TRegKey(const TRegKeyIterator& iter, REGSAM /*samDesired*/)
#else
TRegKey::TRegKey(const TRegKeyIterator& iter, REGSAM samDesired)
#endif
:
Key(0),
Name(new _TCHAR[_MAX_PATH+1])
{
iter.BaseKey().EnumKey(iter.Current(), Name, _MAX_PATH+1);
#if defined(BI_PLAT_WIN16)
::RegOpenKey(iter.BaseKey(), Name, &Key);
#else
::RegOpenKeyEx(iter.BaseKey(), Name, 0, samDesired, &Key);
#endif
ShouldClose = true;
QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
}
//
// Construct a TRegKey object around an existing key. Commonly used for
// wrapping the preexisting pseudo-keys.
//
TRegKey::TRegKey(THandle aliasKey, bool shouldClose, const _TCHAR far* keyName)
:
Key(aliasKey),
Name(strnewdup(keyName))
{
ShouldClose = shouldClose;
#if defined(BI_PLAT_WIN16)
long err = QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
if (err != S_OK)
Key = 0;
#else
# if defined(BI_COMP_MSC)
__try {
# else
try {
# endif
long err = QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
if (err != S_OK && err != ERROR_INSUFFICIENT_BUFFER)
Key = 0;
}
// Some key handles are unsupported & sometimes the OS crashes, & doesn't
// just return an error. Catch it here & zero out this key.
//
__except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
Key = 0;
}
#endif
}
//
// Destructor closes the key if necessary and deletes any previously
// allocated memory by the object.
//
TRegKey::~TRegKey()
{
if (Key && ShouldClose)
::RegCloseKey(Key);
delete[] Name;
}
#if defined(BI_PLAT_WIN16)
//
// Query information about the key.
// Emulation for 16-bits.
//
long
TRegKey::QueryInfo(_TCHAR far* /*class_*/, uint32* /*classSize*/,
uint32* subkeyCount,
uint32* /*maxSubkeySize*/, uint32* /*maxClassSize*/,
uint32* valueCount, uint32* /*maxValueName*/,
uint32* /*maxValueData*/, uint32* /*secDescSize*/,
FILETIME far* /*lastWriteTime*/)
{
// Ug. Enum all subkeys to count them ahead of time for iterator
//
if (subkeyCount) {
int i = 0;
for (;; i++) {
_TCHAR dummy[_MAX_PATH+1];
long r = ::RegEnumKey(Key, i, dummy, sizeof dummy);
if (r != 0/* && r != ERROR_MORE_DATA*/)
break;
}
*subkeyCount = i;
}
if (valueCount)
*valueCount = 1; // Cannot access named values with Win16 API
return 0;
}
#else
//
// Wrapper for RegQueryInfoKey API.
//
long
TRegKey::QueryInfo(_TCHAR far* class_, uint32* classSize,
uint32* subkeyCount, uint32* maxSubkeySize,
uint32* maxClassSize, uint32* valueCount,
uint32* maxValueName, uint32* maxValueData,
uint32* secDescSize, PFILETIME lastWriteTime)
{
_TCHAR db[256];
uint32 d1 = sizeof db;
uint32 d2 = 0;
uint32 d3 = 0;
uint32 d4 = 0;
uint32 d5 = 0;
uint32 d6 = 0;
uint32 d7 = 0;
uint32 d8 = 0;
FILETIME ft;
// NT 3.50 has trouble with 0 ptrs for some of these
//
return ::RegQueryInfoKey(Key, class_ ? class_ : db,
classSize ? classSize : &d1, 0,
subkeyCount ? subkeyCount : &d2,
maxSubkeySize ? maxSubkeySize : &d3,
maxClassSize ? maxClassSize : &d4,
valueCount ? valueCount : &d5,
maxValueName ? maxValueName : &d6,
maxValueData ? maxValueData : &d7,
secDescSize ? secDescSize : &d8,
lastWriteTime ? lastWriteTime : &ft);
}
#endif
//
// Completely nuke a child key, including any of its subkeys. RegDeleteKey
// fails if a key has subkeys, so must tail-recurse to clean them up first.
//
long
TRegKey::NukeKey(const _TCHAR far* subKeyName)
{
{
TRegKey subKey(*this, subKeyName, KEY_ALL_ACCESS, TRegKey::NoCreate);
// Don't increment since deleting & all subkeys will slide down to 0
//
for (TRegKeyIterator i(subKey); i; ) {
TRegKey subSubKey(i);
if (!subSubKey)
break; // All done, ran out before iterator knew, since deleting
long err = subKey.NukeKey(subSubKey.GetName());
if (err)
return err;
}
}
return DeleteKey(subKeyName);
}
//
// Create a value object named 'name' associated with the the current key.
//
TRegValue::TRegValue(const TRegKey& key, const _TCHAR far* name)
:
Key(key), Name(name), AName(0), Data(0)
{
DataSize = 0;
Key.QueryValue(Name, &DataType, 0, &DataSize); // Get type & size only
}
//
// Create a value object pointed to by the current position of the iterator.
//
TRegValue::TRegValue(const TRegValueIterator& iter)
:
Key(iter.BaseKey()), Data(0)
{
uint32 nameSize = _MAX_PATH; //0;
Name = AName = new _TCHAR[(int)nameSize];
DataSize = 0;
Key.EnumValue(iter.Current(), AName, nameSize, &DataType, 0, &DataSize);
}
//
// Destructor deletes any previously allocated memory.
//
TRegValue::~TRegValue()
{
delete[] AName;
delete[] Data;
}
//
// Retrieve the data for the value.
//
void
TRegValue::RetrieveOnDemand() const
{
if (!Data) {
#if defined(BI_NO_MUTABLE)
CONST_CAST(TRegValue*,this)->Data = new uint8[DataSize];
#else
Data = new uint8[(int)DataSize];
#endif
uint32 ds = DataSize;
Key.QueryValue(Name, 0, Data, &ds); // DataSize shouldn't change...
}
}
//
// Set the data for the value.
//
long
TRegValue::Set(uint32 type, uint8* data, uint32 dataSize)
{
long ret = Key.SetValue(Name, type, data, dataSize);
if (ret == 0) {
DataType = type;
if (dataSize == DataSize) {
memcpy(Data, data, (int)DataSize); // resync w/ new data if same size
}
else {
DataSize = dataSize; // Otherwise retrieve on demand later
delete[] Data;
Data = 0;
}
}
return ret;
}
//----------------------------------------------------------------------------
//
// Registry exception checking. Throw a TXRegistry if arg is non-zero
//
void
TXRegistry::Check(long stat, const _TCHAR* key)
{
if (stat != 0 && !InstanceCount) {
if (stat == 1) // default bool true to a generic E_FAIL
stat = E_FAIL;
_TCHAR buf[100];
if (key)
wsprintf(buf, "Registry failure on key: %s, ErrorCode = %lX\n",
(const _TCHAR far*)key, stat);
else
wsprintf(buf, "Registry failure on unknown key: ErrorCode = %lX\n",
stat);
WARN(stat != 0, buf);
throw TXRegistry(buf, key);
}
}
//----------------------------------------------------------------------------
//
// Initialize object with the passed-in data.
// Counts the number of items in the list.
//
TRegTemplateList::TRegTemplateList(TRegKey& basekey, const _TCHAR* list[])
:
BaseKey(basekey),
List(list)
{
PRECONDITION(List);
for (Count = 0; List[Count]; Count++)
;
EnabledFlags = new _TCHAR[Count];
}
//
// Destructor deletes any previously allocated memory.
//
TRegTemplateList::~TRegTemplateList()
{
delete[] EnabledFlags;
}
//
// Enable items from the set.
//
void
TRegTemplateList::Enable(const _TCHAR* set)
{
for (const _TCHAR* pc = set; *pc != 0; pc++)
EnabledFlags[*pc - 1] = 0; // Selectively allow enable
}
//
// Activate the items in the set.
//
void
TRegTemplateList::Activate(const _TCHAR* set)
{
for (const _TCHAR* pc = set; *pc != 0; pc++)
EnabledFlags[*pc - 1]++;
}
//----------------------------------------------------------------------------
//
// Initialize the object with the passed-in data.
// Counts the number of items in the list.
//
TRegParamList::TRegParamList(TEntry* list)
:
List(list)
{
PRECONDITION(List);
for (Count = 0; List[Count].Param; Count++)
;
typedef const _TCHAR* cpchar;
Values = new cpchar[Count];
}
//
// Destructor deletes any previously allocated memory.
//
TRegParamList::~TRegParamList()
{
delete[] Values;
}
//
// Reset all values to their default values.
//
void
TRegParamList::ResetDefaultValues()
{
for (int i = Count; --i >= 0; )
Values[i] = List[i].Default;
}
//
// Look for a given param in this param list
//
int TRegParamList::Find(const _TCHAR* param)
{
PRECONDITION(param);
if (!param)
return -1;
int i = Count;
while (--i >= 0) {
if (_tcscmp(List[i].Param, param) == 0)
break;
}
return i;
}
//----------------------------------------------------------------------------
//
// Initialize the symbol table with the data.
//
TRegSymbolTable::TRegSymbolTable(TRegKey& basekey, const _TCHAR* tplList[],
TRegParamList::TEntry* paramList)
:
Templates(basekey, tplList),
Params(paramList)
{
UserKeyCount = 0;
}
//
// Enable all templates, or if filter is given enable only those
// Initialize paramater values with defaults
//
void
TRegSymbolTable::Init(_TCHAR* filter)
{
if (filter) {
Templates.DisableAll();
Templates.Enable(filter);
}
else {
Templates.EnableAll();
}
Params.ResetDefaultValues();
UserKeyCount = 0;
}
//
// Scan through provided items assinging values from the item to the matching
// param. A langId is needed for locale translation on assignment.
//
void
TRegSymbolTable::UpdateParams(TLangId lang, TRegItem* item)
{
for (; item && item->Key; item++) {
// Note presence of user-specified key and value, process when streaming
//
if (*item->Key == ' ') {
UserKeyCount++;
}
else {
// Replace default with user-specified parameter value
//
int i = Params.Find(item->Key);
TXRegistry::Check(i < 0, item->Key);
Params.Value(i) = item->Value.Translate(lang);
// Activate all templates invoked by parameter
//
Templates.Activate(Params[i].TemplatesNeeded);
}
}
}
//
// Scan thru and process enabled templates, substituting filled in parameter
// values and streaming the resulting strings into the out stream provided.
//
void
TRegSymbolTable::StreamOut(TRegItem* item, ostream& out)
{
for (int itpl = 1; itpl <= Templates.GetCount() || UserKeyCount--; itpl++) {
// Setup pt from standard templates, or from userKeys in item prepended
// by spaces.
//
const _TCHAR* userval = 0;
const _TCHAR* pt;
if (itpl <= Templates.GetCount()) { // Processing standard template array
if (!Templates.IsActive(itpl))
continue;
pt = Templates[itpl];
}
else { // Now processing user-defined templates
while (*(pt = item->Key) != ' ')
item++;
pt++;
userval = item->Value;
}
// Walk thru template (pt) copying it into buf, replacing <params> on the
// way.
//
const int bufSize = 512;
TAPointer<_TCHAR> buf = new _TCHAR[bufSize];
_TCHAR* data = 0; // Optional data for keys-value=data
const _TCHAR* pc; // Point where param token began
_TCHAR* pb = buf; // Working buffer write pointer
for (;;) {
_TCHAR c = *pt++; // Current character being copied
switch (c) {
case '<':
pc = pb; // Remember where param token starts
continue;
case '>': {
*pb = 0; // Terminate param token
// Lookup param in param list
//
int i = Params.Find(pc);
TXRegistry::Check(i < 0, pc); // internal err
// Now get the value obtained above
//
pb = (_TCHAR*)pc; // Move buffer ptr back
TXRegistry::Check((pc = Params.Value(i)) == 0, Params[i].Param);
if (*pc == 0 && *pt == ' ')
pt++;
// Copy value to buf
//
while (*pc != 0)
*pb++ = *pc++;
continue;
}
case '=':
while (*(pb-1) == ' ') // Remove trailing space before =
pb--;
*pb++ = 0; // Terminate keys-value
data = pb; // Rest of pt will be data written from here
while (*pt == ' ')
pt++;
continue;
default:
*pb++ = c; // Copy character to buf. Param name will be overwriten
continue;
case 0:
*pb++ = 0;
if (!userval)
break;
pt = userval;
userval = 0;
data = pb;
continue;
}
if (!c)
break;
}
// Now write out a key with an optional assignment value to output stream
//
out
#if defined(BI_DATA_NEAR)
<< TResId(Templates.GetBaseKey().GetName())
#else
<< Templates.GetBaseKey().GetName()
#endif
<< '\\' << (const _TCHAR*)buf;
if (data)
out << " = " << data;
out << '\n';
}
}
//----------------------------------------------------------------------------
//
// Walk thru an input stream and use "basekey\key\key=data" lines to set
// registry entries
// Has named value support in the form "basekey\key\key|valuename=data"
//
void TRegistry::Update(TRegKey& baseKey, istream& in)
{
// Loop thru all lines in input stream
//
while (!in.eof()) {
// Get line into entry buffer, skip over base key if it exists, ignore line
// if it doesn't
//
_TCHAR entry[512];
in.getline(entry, _tcslen(baseKey.GetName())+1);
if (_tcscmp(entry, baseKey.GetName()) != 0)
continue;
in.getline(entry, 1+1); // Eat the '\' separator
in.getline(entry, sizeof entry);
// Split entry into keys-value and data strings
//
_TCHAR* data = _tcschr(entry, '=');
if (data) {
_TCHAR* pc = data;
while (*(pc-1) == ' ')
pc--;
*pc = 0;
while (*(++data) == ' ')
;
}
else
data = "";
_TCHAR* valName = _tcschr(entry, '|');
if (valName)
*valName++ = 0; // Terminate key at value name separator
// Set default value
//
if (valName) {
TRegKey subKey(baseKey, entry);
TXRegistry::Check(subKey.SetValue(valName, REG_SZ, (const uint8*)data, 0), entry);
}
else {
TXRegistry::Check(baseKey.SetDefValue(entry, REG_SZ, data, 0), entry);
}
}
}
//
// Walk thru an input stream and use "basekey\key\key=data" lines to check
// registry entries.
// Return the number of differences. Zero means a complete match
//
// Has named value support in the form "basekey\key\key|valuename=data"
//
int TRegistry::Validate(TRegKey& baseKey, istream& in)
{
int diffCount = 0;
while (!in.eof()) {
// Get line into entry buffer, skip over hive key if it exists, ignore line
// if it doesn't
//
_TCHAR entry[512];
in.getline(entry, _tcslen(baseKey.GetName())+1); // 1 for '\', 1 for 0
if (_tcscmp(entry, baseKey.GetName()) != 0)
continue;
in.getline(entry, 1+1); // Eat the '\' separator
in.getline(entry, sizeof entry);
// Split entry into keys-value and data strings
//
_TCHAR* data = _tcschr(entry, '=');
if (data) {
_TCHAR* pc = data;
while (*(pc-1) == ' ')
pc--;
*pc = 0;
while (*(++data) == ' ')
;
}
_TCHAR* valName = _tcschr(entry, '|');
if (valName)
*valName = '\\'; // Replace value name separator with \ for query
// Now lookup keys-value part to get its data and see if it matches the
// data value from the instream
//
_TCHAR buf[300];
uint32 bufSize = sizeof buf;
if (baseKey.QueryDefValue(entry, buf, &bufSize) != S_OK
|| (data && _tcscmp(data, buf) != 0))
diffCount++;
}
return diffCount;
}
//
// Unregisters entries given a reglist, an optional overrides regItem.
// Return the # of errors deleting keys
//
int
TRegistry::Unregister(TRegList& regInfo, TUnregParams* params, TRegItem* overrides)
{
int errorCount = 0;
// Loop thru unregister params to nuke each root level key, thus cleaning
// up all nested keys too
//
for (int i = 0; params[i].Name && params[i].BaseKey; i++) {
const _TCHAR* regKey = regInfo[params[i].Name];
// If the param not found & it matches the overrides item, then use that
// value
//
if (!regKey && overrides && _tcscmp(overrides->Key, params[i].Name) == 0)
regKey = overrides->Value;
// If key-value was found, unregister it
//
if (regKey) {
_TCHAR buff[16];
if (params[i].Prepend) { // Special case prepending char to key
buff[0] = '.';
_tcscpy(buff+1, regKey);
regKey = buff;
}
// Nuke the key, using the basekey as a reference point
//
if (params[i].BaseKey->NukeKey(regKey))
errorCount++; // Should throw exception if certain errors?
}
}
return errorCount;
}